home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / GCC 1.37.1r14 / usr / gcc-1.37.1r14 / (gcc-1.37.π) / out-mac.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-08  |  49.2 KB  |  1,771 lines  |  [TEXT/KAHL]

  1. /* Subroutines for insn-output.c for Macintosh.
  2.    Several routines are taken from the generic 68k aux-output,
  3.    the rest of this file is original code.
  4.    Copyright (C) 1987 Free Software Foundation, Inc.
  5.    Copyright (C) 1989, 1990 Apple Computer, Inc.
  6.  
  7. This file is part of GNU CC.
  8.  
  9. GNU CC is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation; either version 1, or (at your option)
  12. any later version.
  13.  
  14. GNU CC is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. GNU General Public License for more details.
  18.  
  19. You should have received a copy of the GNU General Public License
  20. along with GNU CC; see the file COPYING.  If not, write to
  21. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  22.  
  23. #include "config.h"
  24. #include "rtl.h"
  25. #include "regs.h"
  26. #include "hard-reg-set.h"
  27. #include "real.h"
  28. #include "conditions.h"
  29. #include "insn-flags.h"
  30. #include "insn-config.h"
  31. #include "output.h"
  32. #include <stdio.h>
  33.  
  34. int globalize_this;
  35.  
  36. /* Size varies according to cmd option. */
  37.  
  38. int long_double_type_size;
  39.  
  40. /* Index into this array by (register number >> 3) to find the
  41.    smallest class which contains that register.  */
  42. enum reg_class regno_reg_class[]
  43.   = { DATA_REGS, ADDR_REGS, FP_REGS };
  44.  
  45. static rtx find_addr_reg ();
  46.  
  47. #include "tree.h"
  48.  
  49. rtx
  50. function_arg( CUMULATIVE_ARGS *cum, enum machine_mode mode, int named )
  51. {
  52.     int i;
  53.     if ( cum->p == NULL )
  54.         return( 0 );
  55.  
  56.     if(cum->p->params[cum->count]==noreg)
  57.        return( 0 );
  58.     
  59.     if( cum->p->params[cum->count] < 4 )
  60.         i = cum->p->params[cum->count]-1;
  61.     else
  62.         i = cum->p->params[cum->count]+4;
  63.     return( gen_rtx(REG, mode, i ));
  64. }
  65.  
  66. rtx
  67. function_value( tree amode, tree decl )
  68. {
  69.     int i;
  70.     
  71.         if ( (decl == NULL) || ((DECL_PARAM(decl) == NULL) || (DECL_PARAM(decl)->funcreturn==noreg)) )
  72.             if (TARGET_68881 &&  (GET_MODE_CLASS (TYPE_MODE (amode)) == MODE_FLOAT) )
  73.                 return( gen_rtx(REG, TYPE_MODE (amode), 16 ) );
  74.             else
  75.                 return( gen_rtx(REG, TYPE_MODE (amode), 0 ) );
  76.         else {
  77.  
  78.             if( DECL_PARAM(decl)->funcreturn < pa0 )
  79.                 i = DECL_PARAM(decl)->funcreturn-1;
  80.             else
  81.                 i = DECL_PARAM(decl)->funcreturn+4;
  82.         
  83.             return( gen_rtx(REG, TYPE_MODE (amode), i ));
  84.         }
  85.  
  86. }
  87.  
  88. extern int current_function_is_pascal;
  89.  
  90. rtx function_outgoing_value( tree amode, tree decl )
  91. {
  92.     int i;
  93.     
  94.     if( decl != NULL )
  95.         if ( (DECL_PARAM(decl) == NULL) || (DECL_PARAM(decl)->funcreturn==noreg) )
  96.             if( current_function_is_pascal ) {
  97.                 return(  gen_rtx (MEM, TYPE_MODE (amode),
  98.                 gen_rtx (PLUS, Pmode,
  99.                      frame_pointer_rtx,
  100.                      gen_rtx (CONST_INT, VOIDmode, 12345))) );
  101.                 
  102.             }
  103.             else
  104.                 return( function_value( amode, decl ) );
  105.         else {
  106.             if( DECL_PARAM(decl)->funcreturn < pa0 )
  107.                 i = DECL_PARAM(decl)->funcreturn-1;
  108.             else
  109.                 i = DECL_PARAM(decl)->funcreturn+4;
  110.         
  111.             return( gen_rtx(REG, TYPE_MODE (amode), i ));
  112.         }
  113.     else
  114.         return( function_value( amode, decl ) );
  115.  
  116. }
  117.  
  118. function_prologue (fp, size)
  119.      FILE *fp;
  120.      int size;
  121. {
  122.   register int regno;
  123.   char mask[100];
  124.   extern char call_used_regs[];
  125.   extern int frame_pointer_needed;
  126.   int fsize = ((size) + 3) & -4;
  127.  
  128.   if (TARGET_FX30)
  129.     fprintf (fp, "m#start:\n");
  130.   mask[0] = '\0';
  131.   if (frame_pointer_needed)
  132.     {
  133.       if (TARGET_68020 || fsize < 0x8000)
  134.         fprintf (fp, "\tlink a6,#%d\n", -fsize);
  135.       else
  136.     fprintf (fp, TARGET_GAS?"\tlink a6,#0\n\tsubl #%d,sp\n":"\tlink a6,#0\n\tsub.l #%d,sp\n", fsize);
  137.     }
  138.   for (regno = 16; regno < 24; regno++)
  139.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  140.       {
  141.     strcat(mask, reg_names[regno]);
  142.     strcat(mask, "/");
  143.       }
  144.   if (strlen(mask) > 0)
  145.     {
  146.       mask[strlen(mask)-1] = '\0';
  147.       fprintf (fp, "\tfmovem %s,-(sp)\n", mask);
  148.     }
  149.   mask[0] = '\0';
  150.   for (regno = 0; regno < 16; regno++)
  151.     if (regs_ever_live[regno] && ! call_used_regs[regno] &&
  152.         !(frame_pointer_needed && regno == FRAME_POINTER_REGNUM))
  153.       {
  154.     strcat(mask, reg_names[regno]);
  155.     strcat(mask, "/");
  156.       }
  157.   if (TARGET_FX30)
  158.     {
  159.       strcat(mask, reg_names[13]);
  160.       strcat(mask, "/");
  161.     }
  162.   if (strlen(mask) > 0)
  163.     {
  164.       mask[strlen(mask)-1] = '\0';
  165.       if (index(mask, '/') == 0)
  166.     fprintf (fp, TARGET_GAS?"\tmovel %s,sp@-\n":"\tmove.l %s,-(sp)\n", mask);
  167.       else
  168.     fprintf (fp, TARGET_GAS?"\tmoveml %s,sp@-\n":"\tmovem.l %s,-(sp)\n", mask);
  169.     }
  170.   if (TARGET_FX30)
  171.     {
  172.       fprintf (fp, "\tDC.L $4bfb0170 ; lea -> a5\n");
  173.       fprintf (fp, "\tDC.L _StaticDataArea-m#start-*+2\n");
  174.     }
  175.   /* Hook for tracing has to be called after everything else is set up. */
  176.   if (generate_trace_calls)
  177.     {
  178.       if (!TARGET_GAS) fprintf (fp, "\tIMPORT %%_BP\n");
  179.       fprintf (fp, "\tjsr %%_BP\n");
  180.     }
  181. }
  182.  
  183. /* Function epilogue code restores any saved regs and then returns.  There
  184.    are a number of obscure details and different options that can come up. */
  185.  
  186. /* Note the Macsbug symbol output at the end (see Appendix G of Macsbug
  187.    reference for details). */
  188.  
  189. /* Also note that the pascal function return sequence is cribbed from MPW,
  190.    for no particularly deep reason. */
  191.  
  192. function_epilogue (fp, size)
  193.      FILE *fp;
  194.      int size;
  195. {
  196.   register int regno;
  197.   register int nregs;
  198.   int offset, foffset, fpoffset;
  199.   extern char call_used_regs[];
  200.   extern int current_function_pops_args;
  201.   extern int current_function_args_size;
  202.   extern int current_function_is_pascal;
  203.   extern int frame_pointer_needed;
  204.   int fsize = ((size) + 3) & -4;
  205.   int big = 0;
  206.   char mask[100], fmask[100];
  207.  
  208.   /* Have to generate the trace calls after the return result is set up (by function
  209.      body), but before any state restoration happens. */
  210.   if (generate_trace_calls)
  211.     {
  212.       fprintf (fp, TARGET_GAS?"\tmovel d0,sp@-\n":"\tmove.l d0,-(a7)\n");
  213.       if (!TARGET_GAS) fprintf (fp, "\tIMPORT %%_EP\n");
  214.       fprintf (fp, "\tjsr %%_EP\n");
  215.       fprintf (fp, TARGET_GAS?"\tmovel sp@+,d0\n":"\tmove.l (a7)+,d0\n");
  216.     }
  217.   /* Now compute which of all the registers has to be restored. */
  218.   mask[0] = '\0'; fmask[0] = '\0';
  219.   nregs = 0;
  220.   for (regno = 16; regno < 24; regno++)
  221.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  222.       { nregs++; strcat(fmask, reg_names[regno]);  strcat(fmask, "/"); }
  223.   foffset = nregs * 12;
  224.   nregs = 0;
  225.   if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0;
  226.   for (regno = 0; regno < 16; regno++)
  227.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  228.       { nregs++; strcat(mask, reg_names[regno]);  strcat(mask, "/"); }
  229.   if (TARGET_FX30)
  230.     { nregs++; strcat(mask, reg_names[13]);  strcat(mask, "/"); }
  231.   offset = foffset + nregs * 4;
  232.   if (offset + fsize >= 0x8000
  233.       && frame_pointer_needed
  234.       && (strlen(mask) > 0 || strlen(fmask) > 0))
  235.     { fprintf (fp, TARGET_GAS?"\tmovel #%d,a0\n":"\tmove.l #%d,a0\n", -fsize);
  236.       fsize = 0, big = 1; }
  237.   if (strlen(mask) > 0) {
  238.     mask[strlen(mask)-1] = '\0';
  239.     if (index(mask, '/') == 0) {
  240.       if (big)
  241.         fprintf (fp, TARGET_GAS?"\tmovel a6@(-%d,a0:l),%s\n":"\tmove.l (-%d,a6,a0:l),%s\n", offset + fsize, mask);
  242.       else if (! frame_pointer_needed)
  243.         fprintf (fp, TARGET_GAS?"\tmovel sp@+,%s\n":"\tmove.l (sp)+,%s\n", mask);
  244.       else
  245.         fprintf (fp, TARGET_GAS?"\tmovel a6@(-%d),%s\n":"\tmove.l -%d(a6),%s\n", offset + fsize, mask);
  246.     } else {
  247.       if (big)
  248.         fprintf (fp, TARGET_GAS?"\tmoveml a6@(-%d,a0.l),%s\n":"\tmovem.l (-%d,a6,a0.l),%s\n", offset + fsize, mask);
  249.       else if (! frame_pointer_needed)
  250.         fprintf (fp, TARGET_GAS?"\tmoveml sp@+,%s\n":"\tmovem.l (sp)+,%s\n", mask);
  251.       else
  252.         fprintf (fp, TARGET_GAS?"\tmoveml a6@(-%d),%s\n":"\tmovem.l -%d(a6),%s\n", offset + fsize, mask);
  253.     }
  254.   }
  255.   if (strlen(fmask) > 0) {
  256.     fmask[strlen(fmask)-1] = '\0';
  257.     if (big)
  258.       fprintf (fp, "\tfmovem (-%d,a6,a0.l),%s\n", foffset + fsize, fmask);
  259.     else if (! frame_pointer_needed)
  260.       fprintf (fp, "\tfmovem (sp)+,%s\n", fmask);
  261.     else
  262.       fprintf (fp, "\tfmovem -%d(a6),%s\n", foffset + fsize, fmask);
  263.   }
  264.   if (frame_pointer_needed)
  265.     fprintf (fp, "\tunlk a6\n");
  266. /*  if (current_function_pops_args && current_function_args_size)
  267.     fprintf (fp, "\tDC.W $4e74, %d  ; rtd\n",
  268.          current_function_args_size
  269.          + (current_function_returns_struct ? 4 : 0));
  270.   else */ if (current_function_is_pascal && current_function_args_size > 0)
  271.     fprintf (fp, TARGET_GAS?"\tmovel sp@+,a0\n\taddw #%d,sp\n\tjmp a0@\n":"\tmovea.l (sp)+,a0\n\tadd.w #%d,sp\n\tjmp (a0)\n",
  272.          current_function_args_size);
  273. /*  else if (current_function_returns_struct)
  274.     fprintf (fp, "\tDC.W $4e74, 4  ; rtd #4\n"); */
  275.   else
  276.     fprintf (fp, "\trts\n");
  277.   if (TARGET_MACSBUG)
  278.     {
  279.       extern char *current_function_name;
  280.       int len = strlen(current_function_name);
  281.  
  282.       if (len < 32)
  283.         ASM_OUTPUT_BYTE(fp,0x80 + len);
  284.       else
  285.         {
  286.         ASM_OUTPUT_BYTE(fp,0x80);
  287.         ASM_OUTPUT_BYTE(fp,len);
  288.         }
  289.       fprintf (fp, TARGET_GAS?"\t.ascii \"%s\"\n":"\tDC.B '%s'\n", current_function_name);
  290.       if (len < 32) 
  291.             {
  292.             if ((len+1) & 1) ASM_OUTPUT_BYTE(fp,0);
  293.             }
  294.       else
  295.             {
  296.             if ((len+2) & 1) ASM_OUTPUT_BYTE(fp,0);
  297.             }
  298.     }
  299.   /* Unconditional, so the "local data length" gets written properly */
  300.   dump_local_strings (fp);
  301. }
  302.  
  303. char *
  304. output_btst (operands, countop, dataop, insn, signpos)
  305.      rtx *operands;
  306.      rtx countop, dataop;
  307.      rtx insn;
  308.      int signpos;
  309. {
  310.   operands[0] = countop;
  311.   operands[1] = dataop;
  312.   if (GET_CODE (countop) == CONST_INT)
  313.     {
  314.       register int count = INTVAL (countop);
  315.       if (count == signpos)
  316.     cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N;
  317.       else
  318.     cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N;
  319.  
  320.       if (count == 31
  321.       && next_insns_test_no_inequality (insn))
  322.     return "tst%.l %1";
  323.       if (count == 15
  324.       && next_insns_test_no_inequality (insn))
  325.     return "tst%.w %1";
  326.       if (count == 7
  327.       && next_insns_test_no_inequality (insn))
  328.     return "tst%.b %1";
  329.  
  330.       cc_status.flags = CC_NOT_NEGATIVE;
  331.     }
  332.   return "btst %0,%1";
  333. }
  334.  
  335. /* Return the best assembler insn template
  336.    for moving operands[1] into operands[0] as a fullword.  */
  337.  
  338. static char *
  339. singlemove_string (operands)
  340.      rtx *operands;
  341. {
  342.   if (operands[1] != const0_rtx)
  343.     return "move%.l %1,%0";
  344.   if (! ADDRESS_REG_P (operands[0]))
  345.     return "clr%.l %0";
  346.   return "sub%.l %0,%0";
  347. }
  348.  
  349. /* Output assembler code to perform a doubleword move insn
  350.    with operands OPERANDS.  */
  351.  
  352. char *
  353. output_move_double (operands)
  354.      rtx *operands;
  355. {
  356.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  357.   rtx latehalf[2];
  358.   rtx addreg0 = 0, addreg1 = 0;
  359.  
  360.   /* First classify both operands.  */
  361.  
  362.   if (REG_P (operands[0]))
  363.     optype0 = REGOP;
  364.   else if (offsettable_memref_p (operands[0]))
  365.     optype0 = OFFSOP;
  366.   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
  367.     optype0 = POPOP;
  368.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  369.     optype0 = PUSHOP;
  370.   else if (GET_CODE (operands[0]) == MEM)
  371.     optype0 = MEMOP;
  372.   else
  373.     optype0 = RNDOP;
  374.  
  375.   if (REG_P (operands[1]))
  376.     optype1 = REGOP;
  377.   else if (CONSTANT_P (operands[1])
  378.        || GET_CODE (operands[1]) == CONST_DOUBLE)
  379.     optype1 = CNSTOP;
  380.   else if (offsettable_memref_p (operands[1]))
  381.     optype1 = OFFSOP;
  382.   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  383.     optype1 = POPOP;
  384.   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  385.     optype1 = PUSHOP;
  386.   else if (GET_CODE (operands[1]) == MEM)
  387.     optype1 = MEMOP;
  388.   else
  389.     optype1 = RNDOP;
  390.  
  391.   /* Check for the cases that the operand constraints are not
  392.      supposed to allow to happen.  Abort if we get one,
  393.      because generating code for these cases is painful.  */
  394.  
  395.   if (optype0 == RNDOP || optype1 == RNDOP)
  396.     abort ();
  397.  
  398.   /* If one operand is decrementing and one is incrementing
  399.      decrement the former register explicitly
  400.      and change that operand into ordinary indexing.  */
  401.  
  402.   if (optype0 == PUSHOP && optype1 == POPOP)
  403.     {
  404.       operands[0] = XEXP (XEXP (operands[0], 0), 0);
  405.       output_asm_insn ("subq%.l #8,%0", operands);
  406.       operands[0] = gen_rtx (MEM, DImode, operands[0]);
  407.       optype0 = OFFSOP;
  408.     }
  409.   if (optype0 == POPOP && optype1 == PUSHOP)
  410.     {
  411.       operands[1] = XEXP (XEXP (operands[1], 0), 0);
  412.       output_asm_insn ("subq%.l #8,%1", operands);
  413.       operands[1] = gen_rtx (MEM, DImode, operands[1]);
  414.       optype1 = OFFSOP;
  415.     }
  416.  
  417.   /* If an operand is an unoffsettable memory ref, find a register
  418.      we can increment temporarily to make it refer to the second word.  */
  419.  
  420.   if (optype0 == MEMOP)
  421.     addreg0 = find_addr_reg (XEXP (operands[0], 0));
  422.  
  423.   if (optype1 == MEMOP)
  424.     addreg1 = find_addr_reg (XEXP (operands[1], 0));
  425.  
  426.   /* Ok, we can do one word at a time.
  427.      Normally we do the low-numbered word first,
  428.      but if either operand is autodecrementing then we
  429.      do the high-numbered word first.
  430.  
  431.      In either case, set up in LATEHALF the operands to use
  432.      for the high-numbered word and in some cases alter the
  433.      operands in OPERANDS to be suitable for the low-numbered word.  */
  434.  
  435.   if (optype0 == REGOP)
  436.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  437.   else if (optype0 == OFFSOP)
  438.     latehalf[0] = adj_offsettable_operand (operands[0], 4);
  439.   else
  440.     latehalf[0] = operands[0];
  441.  
  442.   if (optype1 == REGOP)
  443.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  444.   else if (optype1 == OFFSOP)
  445.     latehalf[1] = adj_offsettable_operand (operands[1], 4);
  446.   else if (optype1 == CNSTOP)
  447.     {
  448.       if (CONSTANT_P (operands[1]))
  449.     latehalf[1] = const0_rtx;
  450.       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  451.     {
  452.       union { REAL_VALUE_TYPE e; int i[3]; } ue;
  453.       union { double d; int i[2]; } ud;
  454.  
  455.       ue.i[0] = CONST_DOUBLE_LOW (operands[1]);
  456.       ue.i[1] = CONST_DOUBLE_HIGH (operands[1]);
  457.       ue.i[2] = CONST_DOUBLE_TOP (operands[1]);
  458.  
  459.       ud.d = ue.e;
  460.  
  461.       latehalf[1] = gen_rtx (CONST_INT, VOIDmode, ud.i[1]);
  462.       operands[1] = gen_rtx (CONST_INT, VOIDmode, ud.i[0]);
  463.     }
  464.     }
  465.   else
  466.     latehalf[1] = operands[1];
  467.  
  468.   /* If insn is effectively movd N(sp),-(sp) then we will do the
  469.      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
  470.      for the low word as well, to compensate for the first decrement of sp.  */
  471.   if (optype0 == PUSHOP
  472.       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
  473.       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
  474.     operands[1] = latehalf[1];
  475.  
  476.   /* If one or both operands autodecrementing,
  477.      do the two words, high-numbered first.  */
  478.  
  479.   /* Likewise,  the first move would clobber the source of the second one,
  480.      do them in the other order.  This happens only for registers;
  481.      such overlap can't happen in memory unless the user explicitly
  482.      sets it up, and that is an undefined circumstance.  */
  483.  
  484.   if (optype0 == PUSHOP || optype1 == PUSHOP
  485.       || (optype0 == REGOP && optype1 == REGOP
  486.       && REGNO (operands[0]) == REGNO (latehalf[1])))
  487.     {
  488.       /* Make any unoffsettable addresses point at high-numbered word.  */
  489.       if (addreg0)
  490.     output_asm_insn ("addql #4,%0", &addreg0);
  491.       if (addreg1)
  492.     output_asm_insn ("addql #4,%0", &addreg1);
  493.  
  494.       /* Do that word.  */
  495.       output_asm_insn (singlemove_string (latehalf), latehalf);
  496.  
  497.       /* Undo the adds we just did.  */
  498.       if (addreg0)
  499.     output_asm_insn ("subql #4,%0", &addreg0);
  500.       if (addreg1)
  501.     output_asm_insn ("subql #4,%0", &addreg1);
  502.  
  503.       /* Do low-numbered word.  */
  504.       output_asm_insn (singlemove_string (operands), operands);
  505.  
  506.       return "";
  507.     }
  508.  
  509.   /* Normal case: do the two words, low-numbered first.  */
  510.  
  511.   output_asm_insn (singlemove_string (operands), operands);
  512.  
  513.   /* Make any unoffsettable addresses point at high-numbered word.  */
  514.   if (addreg0)
  515.     output_asm_insn ("addql #4,%0", &addreg0);
  516.   if (addreg1)
  517.     output_asm_insn ("addql #4,%0", &addreg1);
  518.  
  519.   /* Do that word.  */
  520.   output_asm_insn (singlemove_string (latehalf), latehalf);
  521.  
  522.   /* Undo the adds we just did.  */
  523.   if (addreg0)
  524.     output_asm_insn ("subql #4,%0", &addreg0);
  525.   if (addreg1)
  526.     output_asm_insn ("subql #4,%0", &addreg1);
  527.  
  528.   return "";
  529. }
  530.  
  531. /* Output assembler code to perform a long double move insn
  532.    with operands OPERANDS.  */
  533.  
  534. char *
  535. output_move_extended (operands)
  536.      rtx *operands;
  537. {
  538.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  539.   rtx latehalf[2], thirdhalf[2];
  540.   rtx addreg0 = 0, addreg1 = 0;
  541.  
  542.   /* First classify both operands.  */
  543.  
  544.   if (REG_P (operands[0]))
  545.     optype0 = REGOP;
  546.   else if (offsettable_memref_p (operands[0]))
  547.     optype0 = OFFSOP;
  548.   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
  549.     optype0 = POPOP;
  550.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  551.     optype0 = PUSHOP;
  552.   else if (GET_CODE (operands[0]) == MEM)
  553.     optype0 = MEMOP;
  554.   else
  555.     optype0 = RNDOP;
  556.  
  557.   if (REG_P (operands[1]))
  558.     optype1 = REGOP;
  559.   else if (CONSTANT_P (operands[1])
  560.        || GET_CODE (operands[1]) == CONST_DOUBLE)
  561.     optype1 = CNSTOP;
  562.   else if (offsettable_memref_p (operands[1]))
  563.     optype1 = OFFSOP;
  564.   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  565.     optype1 = POPOP;
  566.   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  567.     optype1 = PUSHOP;
  568.   else if (GET_CODE (operands[1]) == MEM)
  569.     optype1 = MEMOP;
  570.   else
  571.     optype1 = RNDOP;
  572.  
  573.   /* Check for the cases that the operand constraints are not
  574.      supposed to allow to happen.  Abort if we get one,
  575.      because generating code for these cases is painful.  */
  576.  
  577.   if (optype0 == RNDOP || optype1 == RNDOP || optype0 == MEMOP || optype1 == MEMOP)
  578.     abort ();
  579.  
  580.   /* If one operand is decrementing and one is incrementing
  581.      decrement the former register explicitly
  582.      and change that operand into ordinary indexing.  */
  583.  
  584.   if (optype0 == PUSHOP && optype1 == POPOP)
  585.     {
  586.       operands[0] = XEXP (XEXP (operands[0], 0), 0);
  587.       output_asm_insn ("subq%.l #12345,%0", operands);
  588.       operands[0] = gen_rtx (MEM, DImode, operands[0]);
  589.       optype0 = OFFSOP;
  590.     }
  591.   if (optype0 == POPOP && optype1 == PUSHOP)
  592.     {
  593.       operands[1] = XEXP (XEXP (operands[1], 0), 0);
  594.       output_asm_insn ("subq%.l #12345,%1", operands);
  595.       operands[1] = gen_rtx (MEM, DImode, operands[1]);
  596.       optype1 = OFFSOP;
  597.     }
  598.  
  599.   /* Ok, we can do one word at a time.
  600.      Normally we do the low-numbered word first,
  601.      but if either operand is autodecrementing then we
  602.      do the high-numbered word first.
  603.  
  604.      In either case, set up in LATEHALF the operands to use
  605.      for the high-numbered word and in some cases alter the
  606.      operands in OPERANDS to be suitable for the low-numbered word.  */
  607.  
  608.   if (optype0 == REGOP)
  609.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  610.   else if (optype0 == OFFSOP)
  611.     latehalf[0] = adj_offsettable_operand (operands[0], (TARGET_68881 ? 4 :2));
  612.   else
  613.     latehalf[0] = operands[0];
  614.  
  615.   if (optype1 == REGOP)
  616.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  617.   else if (optype1 == OFFSOP)
  618.     latehalf[1] = adj_offsettable_operand (operands[1], (TARGET_68881 ? 4 :2));
  619.   else if (optype1 == CNSTOP)
  620.     {
  621.       if (CONSTANT_P (operands[1]))
  622.     latehalf[1] = const0_rtx;
  623.       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  624.     {
  625.       latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
  626.                  CONST_DOUBLE_HIGH (operands[1]));
  627.     }
  628.     }
  629.   else
  630.     latehalf[1] = operands[1];
  631.  
  632.   if (optype0 == REGOP)
  633.     thirdhalf[0] = gen_rtx (REG, SImode,
  634.                 ((!TARGET_68881 && REGNO (operands[0]) == 0) ?
  635.                  8 :
  636.                  REGNO (operands[0]) + 2));
  637.   else if (optype0 == OFFSOP)
  638.     thirdhalf[0] = adj_offsettable_operand (operands[0], (TARGET_68881 ? 8:6));
  639.   else
  640.     thirdhalf[0] = operands[0];
  641.  
  642.   if (optype1 == REGOP)
  643.     thirdhalf[1] = gen_rtx (REG, SImode,
  644.                 ((!TARGET_68881 && REGNO (operands[1]) == 0) ?
  645.                  8 :
  646.                  REGNO (operands[1]) + 2));
  647.   else if (optype1 == OFFSOP)
  648.     thirdhalf[1] = adj_offsettable_operand (operands[1], (TARGET_68881 ? 8:6));
  649.   else if (optype1 == CNSTOP)
  650.     {
  651.       if (CONSTANT_P (operands[1]))
  652.     thirdhalf[1] = const0_rtx;
  653.       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  654.     {
  655.       thirdhalf[1] = gen_rtx (CONST_INT, VOIDmode,
  656.                  CONST_DOUBLE_TOP (operands[1]));
  657.       operands[1] = gen_rtx (CONST_INT, VOIDmode,
  658.                  (TARGET_68881 ? CONST_DOUBLE_LOW (operands[1])
  659.                                                  : ((unsigned int) CONST_DOUBLE_LOW (operands[1])) >> 16));
  660.     }
  661.     }
  662.   else
  663.     thirdhalf[1] = operands[1];
  664.  
  665.   /* If insn is effectively movd N(sp),-(sp) then we will do the
  666.      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
  667.      for the low word as well, to compensate for the first decrement of sp.  */
  668.   if (optype0 == PUSHOP
  669.       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
  670.       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
  671.     operands[1] = latehalf[1];
  672.  
  673.   /* If one or both operands autodecrementing,
  674.      do the two words, high-numbered first.  */
  675.  
  676.     
  677.   /* Likewise,  the first move would clobber the source of the second one,
  678.      do them in the other order.  This happens only for registers;
  679.      such overlap can't happen in memory unless the user explicitly
  680.      sets it up, and that is an undefined circumstance.  */
  681.  
  682.   if (optype0 == PUSHOP || optype1 == PUSHOP
  683.       || (optype0 == REGOP && optype1 == REGOP
  684.       && REGNO (operands[0]) == REGNO (latehalf[1])))
  685.     {
  686.       output_asm_insn (singlemove_string (thirdhalf), thirdhalf);
  687.  
  688.       output_asm_insn (singlemove_string (latehalf), latehalf);
  689.  
  690.       if (TARGET_68881)
  691.     output_asm_insn (singlemove_string (operands), operands);
  692.       else
  693.     output_asm_insn ("move%.w %1,%0", operands);
  694.  
  695.       return "";
  696.     }
  697.  
  698.   /* Normal case: do the three words, low-numbered first.  */
  699.  
  700.   if (TARGET_68881)
  701.     output_asm_insn (singlemove_string (operands), operands);
  702.   else
  703.     output_asm_insn ("move%.w %1,%0", operands);
  704.  
  705.   output_asm_insn (singlemove_string (latehalf), latehalf);
  706.  
  707.   output_asm_insn (singlemove_string (thirdhalf), thirdhalf);
  708.  
  709.   return "";
  710. }
  711.  
  712. /* Generate code for one of the extended-to-integer lib calls.  The context
  713.    is such that we can't make call rtxes, and have to do it all manually. */
  714.  
  715. char *
  716. output_lib_convert (operands, name)
  717.      rtx *operands;
  718.      char *name;
  719. {
  720.   rtx aoperands[2];
  721.   char tmpbuf[1000];
  722.   int pushed = 0;
  723.  
  724.   /* What regs need to be saved/restored? probably several... */
  725.   /* Set up a new operand array. */
  726.   aoperands[0] = gen_rtx (MEM, GET_MODE (aoperands[1]),
  727.               gen_rtx (PRE_DEC, Pmode, stack_pointer_rtx));
  728.   aoperands[1] = operands[1];
  729.   /* We need a pointer to the float; try different ways to get one. */
  730.   if (GET_CODE (aoperands[1]) == MEM)
  731.     {
  732.       output_asm_insn ("pea %1", aoperands);
  733.     }
  734.   else if (FP_REG_P (aoperands[1]))
  735.     {
  736.       output_asm_insn ("fmove.x %1,%0", aoperands);
  737.       output_asm_insn (TARGET_GAS?"pea sp@(0)":"pea 0(sp)", NULL);
  738.       pushed = 1;
  739.     }
  740.   else
  741.     {
  742.       output_move_extended (aoperands);
  743.       output_asm_insn (TARGET_GAS?"pea sp@(0)":"pea 0(sp)", NULL);
  744.       pushed = 1;
  745.     }
  746.   /* Do an on-the-spot importation of the libcall name. */
  747.   if (!TARGET_GAS)
  748.     {
  749.     sprintf (tmpbuf, "IMPORT %s", name);
  750.     output_asm_insn (tmpbuf, NULL);
  751.     }
  752.   /* Now go and do it. */
  753.   if (TARGET_FX30)
  754.     sprintf (tmpbuf, "DC.W $61ff ; bsr.l\;DC.L %s-m#start-*", name);
  755.   else
  756.     sprintf (tmpbuf, "jsr %s", name);
  757.   output_asm_insn (tmpbuf, NULL);
  758.   /* If intended result place is not d0, move it there. */
  759.   if (! (REG_P (operands[0]) && REGNO (operands[0]) == 0))
  760.     {
  761.       aoperands[0] = operands[0];
  762.       aoperands[1] = gen_rtx (REG, SImode, 0);
  763.       output_asm_insn (singlemove_string (aoperands), aoperands);
  764.     }
  765.   /* Fix up the stack (we pushed a pointer and maybe an extended float
  766.      for it to point to). */
  767.   sprintf (tmpbuf, "add%.w #%d,sp",
  768.        4 + (pushed ? mode_size[(int) XFmode] : 0));
  769.   output_asm_insn(tmpbuf, NULL);
  770.   return "";
  771. }
  772.  
  773. /* The int library call convention is to use D0 and D1 with output to D0.
  774.    The complication here is that regalloc is already complete, so we have
  775.    to be very careful not to step on any important values.  From md we
  776.    *are* guaranteed that output is a Dn, while input is either Dn or a
  777.    constant, which simplifies things considerably. */
  778.  
  779. /*   (I'm not 100% convinced that this code is correct...) */
  780.  
  781. char *
  782. output_int_lib_call (operands, name)
  783.      rtx *operands;
  784.      char *name;
  785. {
  786.   char tmpbuf[1000];
  787.   int o0d0 = 0, o2d0 = 0, o0d1 = 0, o2d1 = 0, o0d2 = 0;
  788.  
  789.   /* Int lib routines may step on a0. */
  790.   output_asm_insn (TARGET_GAS?"moveml a0/a1,sp@-":"movem.l a0/a1,-(sp)", NULL);
  791.  
  792.   if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 0) o0d0 = 1;
  793.   if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 1) o0d1 = 1;
  794.   if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 2) o0d2 = 1;
  795.   if (GET_CODE (operands[2]) == REG && REGNO (operands[2]) == 0) o2d0 = 1;
  796.   if (GET_CODE (operands[2]) == REG && REGNO (operands[2]) == 1) o2d1 = 1;
  797.  
  798.     if (!o0d1)
  799.         output_asm_insn (TARGET_GAS?"movel d1,sp@-":"move.l d1,-(sp)", NULL);
  800.  
  801.     if (!o0d2)
  802.         output_asm_insn (TARGET_GAS?"movel d2,sp@-":"move.l d2,-(sp)", NULL);
  803.  
  804.     if (o0d0)
  805.     {
  806.         if (o2d1)
  807.         {
  808.             /* everything is exactly where we want it */
  809.         } 
  810.         else
  811.         {
  812.             /* move operand 2 into d1. */
  813.             output_asm_insn ("move%.l %2,d1", operands);
  814.         }
  815.     }
  816.     else
  817.     {
  818.         /* operand 0 is not in d0, so we need to save d0 on the stack before
  819.            copying the operand to d0. */
  820.         output_asm_insn (TARGET_GAS?"movel d0,sp@-":"move.l d0,-(sp)", NULL);
  821.         if (o0d1) 
  822.         {
  823.             output_asm_insn ("move%.l d1,d0", NULL);
  824.             if (o2d0) 
  825.             {
  826.                 /* Input and output are in exactly the opposite of where we want. */
  827.                 /* d0 just got saved on the stack, so we can copy it from the stack
  828.                    to d1.  Note that we are copying the value not popping it off, so
  829.                    that we can restore d0 later. */
  830.                 output_asm_insn (TARGET_GAS?"movel sp@,d1":"move.l (sp),d1", NULL);
  831.             } 
  832.             else 
  833.             {
  834.                 /* move the input to d1. */
  835.                 output_asm_insn ("movel %2,d1", operands);
  836.             }
  837.         } 
  838.         else 
  839.         {
  840.             if (!o2d1)
  841.             {
  842.                 /* operand 2 is not in d1, so we gotta move it to d1 */
  843.                 output_asm_insn ("move%.l %2,d1", operands);
  844.             }
  845.             /* operand 0 is not in either d0 or d1, so we gotta move it to d0 */
  846.             output_asm_insn ("move%.l %0,d0", operands);
  847.         }
  848.     }
  849.  
  850.   /* Do the int lib call proper now. */
  851.   if (!TARGET_GAS)
  852.     {
  853.     sprintf (tmpbuf, "IMPORT %s", name);
  854.     output_asm_insn (tmpbuf, NULL);
  855.     }
  856.   if (TARGET_FX30)
  857.     sprintf (tmpbuf, "DC.W $61ff ; bsr.l\;DC.L %s-m#start-*", name);
  858.   else
  859.     sprintf (tmpbuf, "jsr %s", name);
  860.   output_asm_insn (tmpbuf, NULL);
  861.  
  862.   /* Now clean up any mess we might have made on the stack, plus move the
  863.      result from d0 to wherever it was supposed to go. */
  864.  
  865.   /* If operand 0 was not in d0, move the output to the correct place and then
  866.        restore d0 */
  867.   if (!o0d0)
  868.     {
  869.     output_asm_insn ("move%.l d0,%0", operands);
  870.     output_asm_insn (TARGET_GAS?"movel sp@+,d0":"move.l (sp)+,d0", NULL);
  871.     }
  872.  
  873.   if (!o0d2)
  874.     output_asm_insn (TARGET_GAS?"movel sp@+,d2":"move.l (sp)+,d2", NULL);
  875.  
  876.   if (!o0d1)
  877.     output_asm_insn (TARGET_GAS?"movel sp@+,d1":"move.l (sp)+,d1", NULL);
  878.     
  879.   /* restore a0, a1, d1, and d2 */
  880.   output_asm_insn (TARGET_GAS?"moveml sp@+,a0/a1":"movem.l (sp)+,a0/a1", NULL);
  881.  
  882.   return "";
  883. }
  884.  
  885. /* Helper stuff for SANE output routines. */
  886.  
  887. #define STKOFF(MODE,OFF)  \
  888.   gen_rtx (MEM, (MODE), gen_rtx (PLUS, Pmode, stack_pointer_rtx,  \
  889.                    gen_rtx (CONST_INT, VOIDmode, (OFF))))
  890.  
  891. /* This takes a stack reference and changes it into a stack reference
  892.    4 bytes deeper.  This is needed after a push on the stack. */
  893.  
  894. rtx deepen (x)
  895.      rtx x;
  896. {
  897.   if (GET_CODE (x) == MEM
  898.       && GET_CODE (XEXP (x, 0)) == PLUS
  899.       && XEXP (XEXP (x, 0), 0) == stack_pointer_rtx)
  900.     {
  901.       return STKOFF (GET_MODE (x), 4 + INTVAL (XEXP (XEXP (x, 0), 1)));
  902.     }
  903.   else
  904.     return x;
  905. }
  906.  
  907. /* Output a 2(1)-address operation that uses SANE. */
  908.  
  909. char *
  910. output_sane_2 (opnds, op, name)
  911.      rtx *opnds;
  912.      int op;
  913.      char *name;
  914. {
  915.   char tmpbuf[100], *cname;
  916.   enum machine_mode mode0 = GET_MODE (opnds[0]);
  917.   int space0 = 0, spacetmp = 0, space;
  918.   int cop;
  919.   rtx operands[2], moperands[2], coperands[2], tmprtx;
  920.  
  921.   if (mode0 != XFmode)
  922.     spacetmp = GET_MODE_SIZE (XFmode);
  923.   if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
  924.     space0 = GET_MODE_SIZE (GET_MODE (opnds[0]));
  925.   space = spacetmp + space0;
  926.   /* Reserve needed space for all our tmps and operands. */
  927.   if (spacetmp > 0)
  928.     {
  929.       sprintf(tmpbuf,"sub%.w #%d,sp", spacetmp);
  930.       output_asm_insn(tmpbuf, NULL);
  931.       tmprtx = STKOFF (XFmode, space0);
  932.     }
  933.   if (space0 > 0)
  934.     {
  935.       output_sane_push(opnds[0]);
  936.       operands[0] = STKOFF (GET_MODE (opnds[0]), 0);
  937.     }
  938.   else
  939.     {
  940.       operands[0] = opnds[0];
  941.     }
  942.   /* Now everything is a pointer to memlocs where the numbers reside. */
  943.   /* First order of business is to make sure the input-output operand
  944.      is of extended type.  If not, then we convert into a reserved place
  945.      and if so, we maybe put it on the stack anyway. */
  946.   if (mode0 != XFmode)
  947.     {
  948.       cop = (mode0 == HImode ? 0x200e :
  949.          (mode0 == SImode ? 0x280e :
  950.           (mode0 == SFmode ? 0x100e :
  951.            0x080e)));
  952.       cname = (mode0 == HImode ? "FI2X" :
  953.            (mode0 == SImode ? "FL2X" :
  954.         (mode0 == SFmode ? "FS2X" :
  955.          "FD2X")));
  956.       coperands[1] = operands[0];
  957.       coperands[0] = deepen (tmprtx);
  958.       output_sane_op (coperands, 2, cop, cname);
  959.       moperands[0] = tmprtx;
  960.     }
  961.   else
  962.     {
  963.       moperands[0] = operands[0];
  964.     }
  965.   /* Now we're all set to do the operation proper. */
  966.   output_sane_op (moperands, 1, op, name);
  967.   /* The result of the operation is still extended, so we may need to
  968.      do another conversion.  Fortunately, the extended result is already in
  969.      memory, so we don't need to allocate, but the final result may need
  970.      to be sent back to regs. */
  971.   if (mode0 != XFmode)
  972.     {
  973.       cop = (mode0 == HImode ? 0x2010 :
  974.          (mode0 == SImode ? 0x2810 :
  975.           (mode0 == SFmode ? 0x1010 :
  976.            0x0810)));
  977.       cname = (mode0 == HImode ? "FX2I" :
  978.            (mode0 == SImode ? "FX2L" :
  979.         (mode0 == SFmode ? "FX2S" :
  980.          "FX2D")));
  981.       coperands[0] = deepen (operands[0]);
  982.       coperands[1] = moperands[0];
  983.       output_sane_op (coperands, 2, cop, cname);
  984.     }
  985.   /* SANE calls all done, now clean up. */
  986.   /* Pop the result if it had to be pushed originally. */
  987.   if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
  988.     {
  989.       output_sane_pop (opnds[0]);
  990.     }
  991.   /* Deallocate everything else. */
  992.   if (spacetmp > 0)
  993.     {
  994.       sprintf (tmpbuf, "add%.w #%d,sp", spacetmp);
  995.       output_asm_insn(tmpbuf, NULL);
  996.     }
  997.   /* All the code has already been dumped out. */
  998.   return "";
  999. }
  1000.  
  1001. /* Output a compare operation that uses SANE (two float operands, integer
  1002.    result). */
  1003.  
  1004. char *
  1005. output_sane_cmp (opnds, op, name)
  1006.      rtx *opnds;
  1007.      int op;
  1008.      char *name;
  1009. {
  1010.   char tmpbuf[100], *cname;
  1011.   enum machine_mode mode0 = GET_MODE (opnds[0]);
  1012.   enum machine_mode mode1 = GET_MODE (opnds[1]);
  1013.   int space0 = 0, space1 = 0, spacetmp = 0, space;
  1014.   int cop;
  1015.   rtx operands[3], moperands[3], coperands[2], tmprtx, tmpop;
  1016.  
  1017.   if (mode0 != XFmode)
  1018.     spacetmp = GET_MODE_SIZE (XFmode);
  1019.   if (REG_P (opnds[0])  || GET_CODE (opnds[0]) == CONST_DOUBLE)
  1020.     space0 = GET_MODE_SIZE (GET_MODE (opnds[0]));
  1021.   if (REG_P (opnds[1]) || GET_CODE (opnds[1]) == CONST_DOUBLE)
  1022.     space1 = GET_MODE_SIZE (GET_MODE (opnds[1]));
  1023.   space = spacetmp + space1 + space0;
  1024.   /* Reserve needed space for all our tmps and operands. */
  1025.   if (spacetmp > 0)
  1026.     {
  1027.       sprintf(tmpbuf, "sub%.w #%d,sp", spacetmp);
  1028.       output_asm_insn(tmpbuf, NULL);
  1029.       tmprtx = STKOFF (XFmode, space0 + space1);
  1030.     }
  1031.   if (space1 > 0)
  1032.     {
  1033.       output_sane_push(opnds[1]);
  1034.       operands[1] = STKOFF (GET_MODE (opnds[1]), space0);
  1035.     }
  1036.   else
  1037.     {
  1038.       operands[1] = opnds[1];
  1039.     }
  1040.   if (space0 > 0)
  1041.     {
  1042.       output_sane_push(opnds[0]);
  1043.       operands[0] = STKOFF (GET_MODE (opnds[0]), 0);
  1044.     }
  1045.   else
  1046.     {
  1047.       operands[0] = opnds[0];
  1048.     }
  1049.   /* Now everything is a pointer to memlocs where the numbers reside. */
  1050.   /* First order of business is to make sure the first operand
  1051.      is of extended type.  If not, then we convert into a reserved place
  1052.      and if so, we maybe put it on the stack anyway. */
  1053.   if (mode0 != XFmode)
  1054.     {
  1055.       cop = (mode0 == HImode ? 0x200e :
  1056.          (mode0 == SImode ? 0x280e :
  1057.           (mode0 == SFmode ? 0x100e :
  1058.            0x080e)));
  1059.       cname = (mode0 == HImode ? "FI2X" :
  1060.            (mode0 == SImode ? "FL2X" :
  1061.         (mode0 == SFmode ? "FS2X" :
  1062.          "FD2X")));
  1063.       coperands[1] = operands[0];
  1064.       coperands[0] = deepen (tmprtx);
  1065.       output_sane_op (coperands, 2, cop, cname);
  1066.       moperands[0] = tmprtx;
  1067.     }
  1068.   else
  1069.     {
  1070.       moperands[0] = operands[0];
  1071.     }
  1072.   tmpop = moperands[0];
  1073.   moperands[0] = deepen (moperands[0]);
  1074.   moperands[1] = operands[1];
  1075.   /* Now we're all set to do the comparison proper. */
  1076.   output_sane_op (moperands, 2, op, name);
  1077.   /* Deallocate everything else.  Note that this add is really adda,
  1078.      so condition codes coming back from SANE op are still valid. */
  1079.   if (spacetmp + space1 + space0 > 0)
  1080.     {
  1081.       sprintf (tmpbuf, "add%.w #%d,sp", spacetmp + space1 + space0);
  1082.       output_asm_insn(tmpbuf, NULL);
  1083.     }
  1084.   /* All the code has already been dumped out. */
  1085.   return "";
  1086. }
  1087.  
  1088. /* Output a compare against 0 by synthesizing the zero and calling cmp. */
  1089.  
  1090. char *
  1091. output_sane_tst (opnds, op, name)
  1092.      rtx *opnds;
  1093.      int op;
  1094.      char *name;
  1095. {
  1096.   enum machine_mode mode0 = GET_MODE (opnds[0]);
  1097.   rtx operands[2];
  1098.  
  1099.   operands[0] = opnds[0];
  1100.   operands[1] = CONST0_RTX (mode0);
  1101.   return output_sane_cmp (operands, op, name);
  1102. }
  1103.  
  1104. /* Output a conversion operation that uses SANE.  This is sort of like
  1105.    a two-address operation, except that conversions aren't needed... */
  1106.  
  1107. char *
  1108. output_sane_convert (opnds)
  1109.      rtx *opnds;
  1110. {
  1111.   char tmpbuf[100], *cname;
  1112.   enum machine_mode frommode = GET_MODE (opnds[1]);
  1113.   enum machine_mode tomode   = GET_MODE (opnds[0]);
  1114.   int space0 = 0, space1 = 0, spacetmp = 0, space;
  1115.   int cop;
  1116.   rtx operands[3], moperands[3], coperands[2], tmprtx, tmpop;
  1117.  
  1118.   if (frommode == tomode) abort();  /* should never happen? */
  1119.  
  1120.   if (frommode != XFmode && tomode != XFmode)
  1121.     spacetmp = GET_MODE_SIZE (XFmode);
  1122.   if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
  1123.     space0 = GET_MODE_SIZE (GET_MODE (opnds[0]));
  1124.   if (REG_P (opnds[1]) || GET_CODE (opnds[1]) == CONST_DOUBLE)
  1125.     space1 = GET_MODE_SIZE (GET_MODE (opnds[1]));
  1126.   space = spacetmp + space1 + space0;
  1127.   /* Reserve needed space for all our tmps and operands. */
  1128.   if (spacetmp > 0)
  1129.     {
  1130.       sprintf(tmpbuf, "sub%.w #%d,sp", spacetmp);
  1131.       output_asm_insn(tmpbuf, NULL);
  1132.       tmprtx = STKOFF (XFmode, space0 + space1);
  1133.     }
  1134.   if (space1 > 0)
  1135.     {
  1136.       output_sane_push(opnds[1]);
  1137.       operands[1] = STKOFF (GET_MODE (opnds[1]), space0);
  1138.     }
  1139.   else
  1140.     {
  1141.       operands[1] = opnds[1];
  1142.     }
  1143.   if (space0 > 0)
  1144.     {
  1145.       output_sane_push(opnds[0]);
  1146.       operands[0] = STKOFF (GET_MODE (opnds[0]), 0);
  1147.     }
  1148.   else
  1149.     {
  1150.       operands[0] = opnds[0];
  1151.     }
  1152.   if (frommode != XFmode)
  1153.     {
  1154.       cop = (frommode == HImode ? 0x200e :
  1155.          (frommode == SImode ? 0x280e :
  1156.           (frommode == SFmode ? 0x100e :
  1157.            0x080e)));
  1158.       cname = (frommode == HImode ? "FI2X" :
  1159.            (frommode == SImode ? "FL2X" :
  1160.         (frommode == SFmode ? "FS2X" :
  1161.          "FD2X")));
  1162.       coperands[1] = operands[1];
  1163.       coperands[0] = deepen (tomode == XFmode ? operands[0] : tmprtx);
  1164.       output_sane_op (coperands, 2, cop, cname);
  1165.     }
  1166.   /* If necessary, do the second conversion. */
  1167.   if (tomode != XFmode)
  1168.     {
  1169.       cop = (tomode == HImode ? 0x2010 :
  1170.          (tomode == SImode ? 0x2810 :
  1171.           (tomode == SFmode ? 0x1010 :
  1172.            0x0810)));
  1173.       cname = (tomode == HImode ? "FX2I" :
  1174.            (tomode == SImode ? "FX2L" :
  1175.         (tomode == SFmode ? "FX2S" :
  1176.          "FX2D")));
  1177.       coperands[1] = (frommode == XFmode ? operands[1] : tmprtx);
  1178.       coperands[0] = deepen (operands[0]);
  1179.       output_sane_op (coperands, 2, cop, cname);
  1180.     }
  1181.   /* Pop the result if it wasn't memory-resident */
  1182.   if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
  1183.     {
  1184.       output_sane_pop (opnds[0]);
  1185.     }
  1186.   /* Finish cleaning up the stack. */
  1187.   if (spacetmp + space1 > 0)
  1188.     {
  1189.       sprintf (tmpbuf, "add%.w #%d,sp", spacetmp + space1);
  1190.       output_asm_insn(tmpbuf, NULL);
  1191.     }
  1192.   return "";
  1193. }
  1194.  
  1195. /* Output a 3(2)-address operation that uses SANE.  This routine will do
  1196.    everything including type conversions, since this helps it use the
  1197.    stack somewhat more efficiently. */
  1198.  
  1199. char *
  1200. output_sane_3 (opnds, op, name)
  1201.      rtx *opnds;
  1202.      int op;
  1203.      char *name;
  1204. {
  1205.     char tmpbuf[100], *cname;
  1206.     enum machine_mode mode0 = GET_MODE (opnds[0]);
  1207.     enum machine_mode mode2 = GET_MODE (opnds[2]);
  1208.     int space0 = 0, space2 = 0, spacetmp = 0, space;
  1209.     int cop;
  1210.     rtx operands[3], moperands[3], coperands[2], tmprtx, tmpop;
  1211.  
  1212.     if (mode0 != XFmode)
  1213.       spacetmp = GET_MODE_SIZE (XFmode);
  1214.     if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
  1215.       space0 = GET_MODE_SIZE (GET_MODE (opnds[0]));
  1216.     if (REG_P (opnds[2]) || GET_CODE (opnds[2]) == CONST_DOUBLE)
  1217.       space2 = GET_MODE_SIZE (GET_MODE (opnds[2]));
  1218.     space = spacetmp + space2 + space0;
  1219.     /* Reserve needed space for all our tmps and operands. */
  1220.     if (spacetmp > 0)
  1221.       {
  1222.     sprintf(tmpbuf, "sub%.w #%d,sp", spacetmp);
  1223.     output_asm_insn(tmpbuf, NULL);
  1224.     tmprtx = STKOFF (XFmode, space0 + space2);
  1225.       }
  1226.     if (space2 > 0)
  1227.       {
  1228.     output_sane_push(opnds[2]);
  1229.     operands[2] = STKOFF (GET_MODE (opnds[2]), space0);
  1230.       }
  1231.     else
  1232.       {
  1233.     operands[2] = opnds[2];
  1234.       }
  1235.     if (space0 > 0)
  1236.       {
  1237.     output_sane_push(opnds[0]);
  1238.     operands[0] = STKOFF (GET_MODE (opnds[0]), 0);
  1239.       }
  1240.     else
  1241.       {
  1242.     operands[0] = opnds[0];
  1243.       }
  1244.     /* Now everything is a pointer to memlocs where the numbers reside. */
  1245.     /* First order of business is to make sure the input-output operand
  1246.        is of extended type.  If not, then we convert into a reserved place
  1247.        and if so, we maybe put it on the stack anyway. */
  1248.     if (mode0 != XFmode)
  1249.       {
  1250.       cop = (mode0 == HImode ? 0x200e :
  1251.          (mode0 == SImode ? 0x280e :
  1252.           (mode0 == SFmode ? 0x100e :
  1253.            0x080e)));
  1254.       cname = (mode0 == HImode ? "FI2X" :
  1255.            (mode0 == SImode ? "FL2X" :
  1256.             (mode0 == SFmode ? "FS2X" :
  1257.              "FD2X")));
  1258.     coperands[1] = operands[0];
  1259.     coperands[0] = deepen (tmprtx);
  1260.     output_sane_op (coperands, 2, cop, cname);
  1261.     moperands[0] = tmprtx;
  1262.       }
  1263.     else
  1264.       {
  1265.     moperands[0] = operands[0];
  1266.       }
  1267.     tmpop = moperands[0];
  1268.     moperands[0] = deepen (moperands[0]);
  1269.     moperands[1] = operands[2];
  1270.     /* Now we're all set to do the operation proper. */
  1271.     output_sane_op (moperands, 2, op, name);
  1272.     /* The result of the operation is still extended, so we may need to
  1273.        do another conversion.  Fortunately, the extended result is already in
  1274.        memory, so we don't need to allocate, but the final result may need
  1275.        to be sent back to regs. */
  1276.     if (mode0 != XFmode)
  1277.       {
  1278.       cop = (mode0 == HImode ? 0x2010 :
  1279.          (mode0 == SImode ? 0x2810 :
  1280.           (mode0 == SFmode ? 0x1010 :
  1281.            0x0810)));
  1282.       cname = (mode0 == HImode ? "FX2I" :
  1283.            (mode0 == SImode ? "FX2L" :
  1284.             (mode0 == SFmode ? "FX2S" :
  1285.              "FX2D")));
  1286.       coperands[0] = deepen (operands[0]);
  1287.       coperands[1] = tmpop;
  1288.       output_sane_op (coperands, 2, cop, cname);
  1289.       }
  1290.     /* SANE calls all done, now clean up. */
  1291.     /* Pop the result if it had to be pushed originally. */
  1292.     if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
  1293.       {
  1294.     output_sane_pop (opnds[0]);
  1295.       }
  1296.     /* Deallocate everything else. */
  1297.     if (spacetmp + space2 > 0)
  1298.       {
  1299.     sprintf (tmpbuf, "add%.w #%d,sp", spacetmp + space2);
  1300.     output_asm_insn(tmpbuf, NULL);
  1301.       }
  1302.     /* All the code has already been dumped out. */
  1303.     return "";
  1304. }
  1305.  
  1306. /* Push a SANE number onto the stack (usually from a reg). */
  1307.  
  1308. output_sane_push (x)
  1309.      rtx x;
  1310. {
  1311.   rtx pusherands[2];
  1312.  
  1313.   pusherands[0] = gen_rtx (MEM, GET_MODE (x),
  1314.                  gen_rtx (PRE_DEC, Pmode, stack_pointer_rtx));
  1315.   pusherands[1] = x;
  1316.   switch (GET_MODE (x))
  1317.     {
  1318.     case HImode:
  1319.       output_asm_insn ("move%.w %1,%0", pusherands);
  1320.       break;
  1321.     case SImode:
  1322.     case SFmode:
  1323.       output_asm_insn ("move%.l %f1,%0", pusherands);
  1324.       break;
  1325.     case DFmode:
  1326.       output_move_double (pusherands);
  1327.       break;
  1328.     case XFmode:
  1329.       output_move_extended (pusherands);
  1330.       break;
  1331.     default:
  1332.       abort();
  1333.     }
  1334. }
  1335.  
  1336. /* Pop a SANE number off the stack into a given place (most likely a reg). */
  1337.  
  1338. output_sane_pop (x)
  1339.      rtx x;
  1340. {
  1341.   rtx poperands[2];
  1342.  
  1343.   poperands[0] = x;
  1344.   poperands[1] = gen_rtx (MEM, GET_MODE (x),
  1345.               gen_rtx (POST_INC, Pmode, stack_pointer_rtx));
  1346.   switch (GET_MODE (x))
  1347.     {
  1348.     case HImode:
  1349.       output_asm_insn ("move%.w %1,%0", poperands);
  1350.       break;
  1351.     case SImode:
  1352.     case SFmode:
  1353.       output_asm_insn ("move%.l %1,%0", poperands);
  1354.       break;
  1355.     case DFmode:
  1356.       output_move_double (poperands);
  1357.       break;
  1358.     case XFmode:
  1359.       output_move_extended (poperands);
  1360.       break;
  1361.     default:
  1362.       abort();
  1363.     }
  1364. }
  1365.  
  1366. /* Issue the basic SANE calling sequence; push addresses of operands (which
  1367.    must already be in memory), push the op code, then trap.  The trap
  1368.    will pop everything itself, so no cleanup needed. */
  1369.  
  1370. output_sane_op (moperands, numopnds, op, name)
  1371.      rtx *moperands;
  1372.      int numopnds, op;
  1373.      char *name;
  1374. {
  1375.   char tmpbuf[100];
  1376.  
  1377.   if (numopnds > 1) 
  1378.     output_asm_insn ("pea %1", moperands);
  1379.   if (numopnds > 0)
  1380.     output_asm_insn ("pea %0", moperands);
  1381.   sprintf (tmpbuf, TARGET_GAS?"movew #$%x,sp@-  ; %s":"move.w #$%x,-(sp)  ; %s", op, name);
  1382.   output_asm_insn (tmpbuf, NULL);
  1383.   output_asm_insn (TARGET_GAS?".word $a9eb        ; FP68K":"dc.w   $a9eb         ; FP68K", NULL);
  1384. }
  1385.  
  1386. /* Return a REG that occurs in ADDR with coefficient 1.
  1387.    ADDR can be effectively incremented by incrementing REG.  */
  1388.  
  1389. static rtx
  1390. find_addr_reg (addr)
  1391.      rtx addr;
  1392. {
  1393.   while (GET_CODE (addr) == PLUS)
  1394.     {
  1395.       if (GET_CODE (XEXP (addr, 0)) == REG)
  1396.     addr = XEXP (addr, 0);
  1397.       else if (GET_CODE (XEXP (addr, 1)) == REG)
  1398.     addr = XEXP (addr, 1);
  1399.       else if (CONSTANT_P (XEXP (addr, 0)))
  1400.     addr = XEXP (addr, 1);
  1401.       else if (CONSTANT_P (XEXP (addr, 1)))
  1402.     addr = XEXP (addr, 0);
  1403.       else
  1404.     abort ();
  1405.     }
  1406.   if (GET_CODE (addr) == REG)
  1407.     return addr;
  1408.   abort ();
  1409. }
  1410.  
  1411. char *
  1412. output_move_const_long_double (operands)
  1413.      rtx *operands;
  1414. {
  1415.     {
  1416.       int code = standard_68881_constant_p (operands[1]);
  1417.  
  1418.       if (code != 0)
  1419.     {
  1420.       static char buf[40];
  1421.  
  1422.       sprintf (buf, "fmovecr #$%x,%%0", code & 0xff);
  1423.       return buf;
  1424.     }
  1425.       return "fmove.x %1,%0";
  1426.     }
  1427. }
  1428.  
  1429. char *
  1430. output_move_const_double (operands)
  1431.      rtx *operands;
  1432. {
  1433.     {
  1434.       int code = standard_68881_constant_p (operands[1]);
  1435.  
  1436.       if (code != 0)
  1437.     {
  1438.       static char buf[40];
  1439.  
  1440.       sprintf (buf, "fmovecr #$%x,%%0", code & 0xff);
  1441.       return buf;
  1442.     }
  1443.       return "fmove.d %1,%0";
  1444.     }
  1445. }
  1446.  
  1447. char *
  1448. output_move_const_single (operands)
  1449.      rtx *operands;
  1450. {
  1451.     {
  1452.       int code = standard_68881_constant_p (operands[1]);
  1453.  
  1454.       if (code != 0)
  1455.     {
  1456.       static char buf[40];
  1457.  
  1458.       sprintf (buf, "fmovecr #$%x,%%0", code & 0xff);
  1459.       return buf;
  1460.     }
  1461.       return "fmove.s %1,%0";
  1462.     }
  1463. }
  1464.  
  1465. /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
  1466.    from the "fmovecr" instruction.
  1467.    The value, anded with 0xff, gives the code to use in fmovecr
  1468.    to get the desired constant.  */
  1469.  
  1470. /* This seems dubious for MPW... */
  1471.  
  1472. int
  1473. standard_68881_constant_p (x)
  1474.      rtx x;
  1475. {
  1476.   union {double d; int i[2];} u;
  1477.   register double d;
  1478.   u.i[0] = CONST_DOUBLE_LOW (x);
  1479.   u.i[1] = CONST_DOUBLE_HIGH (x);
  1480.   d = u.d;
  1481.  
  1482.   if (d == 0)
  1483.     return 0x0f;
  1484.   /* Note: there are various other constants available
  1485.      but it is a nuisance to put in their values here.  */
  1486.   if (d == 1)
  1487.     return 0x32;
  1488.   if (d == 10)
  1489.     return 0x33;
  1490.   if (d == 100)
  1491.     return 0x34;
  1492.   if (d == 10000)
  1493.     return 0x35;
  1494.   if (d == 1e8)
  1495.     return 0x36;
  1496.   if (GET_MODE (x) == SFmode)
  1497.     return 0;
  1498.   if (d == 1e16)
  1499.     return 0x37;
  1500.   /* larger powers of ten in the constants ram are not used
  1501.      because they are not equal to a `double' C constant.  */
  1502.   return 0;
  1503. }
  1504.  
  1505. /* Print out a string in MPW Asm-approved syntax.  Main trickiness is
  1506.    to recognize non-printing characters and put them out as raw bytes,
  1507.    while keeping as many printable characters in a string as possible
  1508.    (saves space in asm code and makes it more readable too). */
  1509.  
  1510. /* newline/cr character mapping was handled at lex time... */
  1511.  
  1512. output_mpw_string(fp, str, size)
  1513. FILE *fp;
  1514. char *str;
  1515. int size;
  1516. {
  1517.     unsigned char ch;
  1518.     int i,empty = 1;
  1519.  
  1520.     for (i = 0; i < size; ++i)
  1521.       {
  1522.     ch = str[i];
  1523.       if ((ch < ' ') || (ch > '~') || (ch == '"') || (ch == '\''))
  1524.       {
  1525.           if (!empty) fprintf(fp, TARGET_GAS?"\"\n":"'\n");
  1526.           ASM_OUTPUT_BYTE(fp,ch);
  1527.           empty = 1;
  1528.       }
  1529.     else
  1530.       {
  1531.             if (empty) fprintf(fp, TARGET_GAS?"\t.ascii \"":"\tDC.B '");
  1532.         fprintf(fp, "%c", ch);
  1533.             empty = (i > 0 && i % 60 == 0);
  1534.             if (empty) fprintf(fp, TARGET_GAS?"\"\n":"'\n");
  1535.       }
  1536.       }
  1537.   if (!empty) fprintf(fp, TARGET_GAS?"\"\n":"'\n");
  1538.   /* Ending NUL char is part of the string's "size", so doesn't need to be added. */
  1539. }
  1540.  
  1541. /* Print out a floating rtx in some useful way. */
  1542.  
  1543. #include "real.h"
  1544.  
  1545. output_mpw_float (fp, x)
  1546. FILE *fp;
  1547. rtx x;
  1548. {
  1549.   union { REAL_VALUE_TYPE f; int i[3]; } u;
  1550.   double d;
  1551.   float f;
  1552.  
  1553.   u.i[0] = CONST_DOUBLE_LOW (x);
  1554.   u.i[1] = CONST_DOUBLE_HIGH (x);
  1555.   u.i[2] = CONST_DOUBLE_TOP (x);
  1556.  
  1557.   switch (GET_MODE (x))
  1558.     {
  1559.     case SFmode:
  1560.       f = u.f;
  1561.       fprintf (fp, "\"%.9g\"", f);
  1562.       break;
  1563.     case DFmode:
  1564.       d = u.f;
  1565.       fprintf (fp, "\"%.20g\"", d);
  1566.       break;
  1567.     case XFmode:
  1568.       fprintf (fp, "\"%.30g\"", u.f);
  1569.       break;
  1570.     default:
  1571.       abort ();
  1572.     }
  1573. }
  1574.  
  1575. output_mpw_float_as_int (fp, x)
  1576. FILE *fp;
  1577. rtx x;
  1578. {
  1579.   union { REAL_VALUE_TYPE f; int i[3]; } u;
  1580.   union { float f; int i[1]; } u2;
  1581.  
  1582.   u.i[0] = CONST_DOUBLE_LOW (x);
  1583.   u.i[1] = CONST_DOUBLE_HIGH (x);
  1584.   u.i[2] = CONST_DOUBLE_TOP (x);
  1585.  
  1586.   u2.f = u.f;
  1587.  
  1588.   switch (GET_MODE (x))
  1589.     {
  1590.     case SFmode:
  1591.       fprintf (fp, "%d", u2.i[0]);
  1592.       break;
  1593.     case DFmode:
  1594.     case XFmode:
  1595.       fprintf (stderr, "Can't integerize a double or extended const!\n");
  1596.     default:
  1597.       abort ();
  1598.     }
  1599. }
  1600.  
  1601. /* Printing extended floats is a little tricky, since both the compiler and
  1602.    the target machines care about the 10/12-byte size. */
  1603.  
  1604. output_mpw_long_double (fp, x)
  1605. FILE *fp;
  1606. REAL_VALUE_TYPE x;
  1607. {
  1608.   union { REAL_VALUE_TYPE f; short s[6]; } u;
  1609.   int a = 0;
  1610.  
  1611.   u.f = x;
  1612.  
  1613.   fprintf (fp, TARGET_GAS?"\t.word %d,":"\tDC.W %d,", u.s[0]);
  1614.   if (TARGET_68881)
  1615.     {
  1616. #ifdef mc68881
  1617.       fprintf (fp, "%d,", u.s[1]);
  1618.       a = 1;
  1619. #else
  1620.       fprintf (fp, "0,");
  1621.       a = 0;
  1622. #endif
  1623.     }
  1624.   fprintf (fp, "%d,%d,%d,%d  ; %.30g\n",
  1625.        u.s[a+1], u.s[a+2], u.s[a+3], u.s[a+4], x);
  1626. }
  1627.  
  1628. /* We need to recognize all possible references to global data.  */
  1629.  
  1630. global_data_ref_p (addr)
  1631.     rtx addr;
  1632. {
  1633.   switch (GET_CODE (addr))
  1634.     {
  1635.     case SYMBOL_REF:
  1636.       {
  1637.     char *name = XSTR (addr, 0);
  1638.  
  1639.     return (name[0] == '2');
  1640.       }
  1641.     case PLUS:
  1642.       return (global_data_ref_p (XEXP (addr, 0))
  1643.           || global_data_ref_p (XEXP (addr, 1)));
  1644.     case CONST:
  1645.       return global_data_ref_p (XEXP (addr, 0));
  1646.     default:
  1647.       return 0;
  1648.     }
  1649.   return 0;
  1650. }
  1651.  
  1652. /* Test a string to see if it matches any register names.  A few extra
  1653.    tests on individual chars to optimize - a more serious approach would
  1654.    involve a binary search tree or something.  Don't bother unless this
  1655.    can be proved to take significant time!  */
  1656.  
  1657. /* Names not in the regular reg_names list that the assembler knows about
  1658.    and will choke on if you attempt to use them as labels.  */
  1659.  
  1660. char *obscure_reg_names[] = {
  1661.   "sp",
  1662.   "a7",
  1663.   "za7",
  1664.   "pc",
  1665.   "zpc",
  1666.   "ccr",
  1667.   "sr",
  1668.   "usp",
  1669.   "sfc",
  1670.   "dfc",
  1671.   "cacr",
  1672.   "vbr",
  1673.   "caar",
  1674.   "msp",
  1675.   "isp",
  1676.   NULL };
  1677.   
  1678. mpw_register_name (str)
  1679. char *str;
  1680. {
  1681.   int i;
  1682.   extern char* reg_names[];
  1683.  
  1684.   if (str[0] == 'd' || str[0] == 'a' || str[0] == 'f')
  1685.     {
  1686.       for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
  1687.     if (strcmp (str, reg_names[i]) == 0)
  1688.       return 1;
  1689.     }
  1690.   if (str[0] == 'z' && (str[1] == 'd' || str[1] == 'a'))
  1691.     {
  1692.       for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
  1693.     if (strcmp (str, reg_names[i]+1) == 0)
  1694.       return 1;
  1695.     }
  1696.   /* There are other more obscure register names to test as well. */
  1697.   for (i = 0; obscure_reg_names[i]; ++i)
  1698.     if (strcmp (str, obscure_reg_names[i]) == 0)
  1699.       return 1;
  1700.   return 0;
  1701. }
  1702.  
  1703. char *
  1704. avoid_mpw_register_name (name)
  1705.      char *name;
  1706. {
  1707.   int typechar = ('0' <= name[0] && name[0] <= '9');
  1708.   char *newname = name;
  1709.  
  1710.   if (mpw_register_name (name + typechar))
  1711.     {
  1712.       /* should warn that name is being changed. */
  1713.       newname = (char *) xmalloc (strlen (name) + 2);
  1714.       strcpy (newname, name);
  1715.       strcat (newname, "_");
  1716.       warning ("`%s' is a register name; changing to `%s'",
  1717.            name + typechar, newname + typechar);
  1718.     }
  1719.   return newname;
  1720. }
  1721.  
  1722. /* Implementing -b requires saving up strings somewhere. */
  1723.  
  1724. char *lbls[100];
  1725. char *strs[100];
  1726. int lsix = 0;
  1727. int totlen = 0;
  1728.  
  1729. record_a_string(lbl, str)
  1730. char *lbl, *str;
  1731. {
  1732.   if (lsix >= 99) abort ();
  1733.   lbls[lsix] = lbl;
  1734.   strs[lsix] = str;
  1735.   totlen += strlen(str) + 1;
  1736.   totlen += (totlen & 1);   /* keeps it aligned */
  1737.   lsix++;
  1738. }
  1739.  
  1740. /* Functions compiled with -b have all their strings at the end of the
  1741.    function, preceded by a length field. */
  1742.  
  1743. /* Should scan a linked list of strings saved up for this function,
  1744.    not a fixed-size array. */
  1745.  
  1746. dump_local_strings (fp)
  1747. FILE *fp;
  1748. {
  1749.   int i;
  1750.  
  1751.   /* Only really need the length word for debugging, otherwise skip it. */
  1752.   if (TARGET_MACSBUG)
  1753.     fprintf (fp, TARGET_GAS?"\t.word %d\n":"\tDC.W %d\n", totlen);
  1754.   for (i = 0; i < lsix; ++i)
  1755.     {
  1756.       /* String might be referred to from elsewhere within this file. */
  1757.       fprintf (fp, "\tENTRY ");
  1758.       assemble_name (fp, lbls[i]);
  1759.       fprintf (fp, "\n");
  1760.       assemble_name (fp, lbls[i]);
  1761.       output_mpw_string (fp, strs[i], strlen(strs[i])+1);
  1762.       fprintf (fp, "\tALIGN\n");
  1763.     }
  1764.   lsix = totlen = 0;
  1765. }
  1766.  
  1767. int init_out_mac()
  1768. {
  1769. #define INIT_OUT_MAC
  1770. #include "init.c"
  1771. }